#include "mainwidget.h"
#include <QHBoxLayout>
#include <QVBoxLayout>
#include <QFileInfo>
#include <QDebug>

#include <QTextCodec>

MainWidget::MainWidget(QWidget *parent)
    : QWidget(parent)
{
    this->setWindowTitle(tr("文件下载器"));
    this->resize(950, 500);

    createWidget();
    createNetworkManager();

    //下载按钮信号
    connect(btnDownLoad, &QPushButton::clicked, this, &MainWidget::on_btnDownLoad_Clicked);

    //get请求按钮信号
    connect(m_btGetRequest, &QPushButton::clicked, this, &MainWidget::on_btnGet_Clicked);

    //取消按钮信号
    connect(btnCancel, &QPushButton::clicked, this, &MainWidget::on_btnCancel_Clicked);
}

MainWidget::~MainWidget()
{

}

void MainWidget::createWidget()
{
    labAddress = new QLabel(tr("下载地址"));
    lineEditAddr = new QLineEdit(tr("https://down.360safe.com/se/360se13.1.5188.0.exe"));

    QFont font = QFont("sim", 16);
    textEdit = new QTextEdit();
    textEdit->setReadOnly(true);
    textEdit->setFont(font);

    btnDownLoad = new QPushButton(tr("开始下载"));
    btnCancel = new  QPushButton(tr("取消下载"));

    m_btGetRequest = new QPushButton(tr("Get请求"));

    btnCancel->hide();

    progress = new QProgressBar();
    progress->hide();

    QHBoxLayout *laytop = new QHBoxLayout();
    laytop->addWidget(labAddress);
    laytop->addWidget(lineEditAddr);
    laytop->addWidget(btnDownLoad);
    laytop->addWidget(m_btGetRequest);

    QHBoxLayout *layBottom = new QHBoxLayout();
    layBottom->addWidget(progress);
    layBottom->addWidget(btnCancel);

    QVBoxLayout *mainLayout = new QVBoxLayout(this);
    mainLayout->addLayout(laytop);
    mainLayout->addWidget(textEdit);
    mainLayout->addLayout(layBottom);
}

void MainWidget::createNetworkManager()
{
    manager = new QNetworkAccessManager(this);

    connect(manager, SIGNAL(finished(QNetworkReply*)), this, SLOT(requestFinished(QNetworkReply*)));
}

void MainWidget::startRequest(QUrl url)
{
    //get发送一个网络请求 返回网络应答
    reply = manager->get(QNetworkRequest(url));

    //每当有新的数据要读取时 发射信号
    connect(reply, &QNetworkReply::readyRead, this, &MainWidget::httpReadyRead);

    //每当有下载进度更新时 发射信号 更新进度条和文本窗
    connect(reply, &QNetworkReply::downloadProgress, this, &MainWidget::updateProgress);

    //应答处理结束时会发射finished信号
    connect(reply, &QNetworkReply::finished, this, &MainWidget::httpFinished);

    //时间计时开始
    time.start();
}

void MainWidget::on_btnGet_Clicked()
{
    QNetworkRequest request;
    request.setUrl(QUrl("http://www.weather.com.cn/data/sk/101190101.html"));
    reply = manager->get(request);
}

void MainWidget::requestFinished(QNetworkReply* reply) {
    // 获取http状态码
    QVariant statusCode = reply->attribute(QNetworkRequest::HttpStatusCodeAttribute);
    if(statusCode.isValid())
        qInfo() << "status code=" << statusCode.toInt();

    QVariant reason = reply->attribute(QNetworkRequest::HttpReasonPhraseAttribute).toString();
    if(reason.isValid())
        qInfo() << "reason=" << reason.toString();

    QNetworkReply::NetworkError err = reply->error();
    if(err != QNetworkReply::NoError) {
        qInfo() << "Failed: " << reply->errorString();
    }
    else {
        // 获取返回内容
        QByteArray data = reply->readAll();
        //QString str = QTextCodec::codecForName("GBK")->toUnicode(data);
        QString str = QString(data);
        qInfo() << str;
    }
}

void MainWidget::on_btnDownLoad_Clicked()
{
    //从地址栏获取URL
    url = lineEditAddr->text();

    //将URL路径存入QFileInfo类
    QFileInfo info(url.path());

    //从info中得到文件名
    QString fileName(info.fileName());

    //如果没有获取到info
    if(fileName.isEmpty()){
        textEdit->setText(tr("<h2> 下载失败 请检查下载地址!!! </h2>"));
        fileName = "index.html";
    }
    else{
        //建立文件
        file = new QFile(fileName);

        //如果文件没有打开的情况
        if(!file->open((QIODevice::WriteOnly))){
            delete file;
            file = nullptr;
            return;
        }

        //执行网络请求函数
        startRequest(url);

        //部件操作
        textEdit->clear();
        progress->setValue(0);
        progress->show();
        btnCancel->show();
    }
}

void MainWidget::on_btnCancel_Clicked()
{
    reply->deleteLater();
    reply = nullptr;

    file->close();
    file = nullptr;

    this->close();
}

void MainWidget::httpReadyRead()
{

    if(file)
        file->write(reply->readAll());
}

void MainWidget::httpFinished()
{
    progress->hide();
    btnCancel->hide();
    textEdit->append(tr("下载完成"));

    if(file){
        file->close();
        delete file;
        file = nullptr;
    }

    reply->deleteLater();
    reply = nullptr;
}

void MainWidget::updateProgress(qint64 bytesReceived, qint64 bytesTotal)
{
    //将qint64的数据转为MB 并且转为String
    QString strReceived = QString::number(bytesReceived / (1024 * 1024));
    QString strTotal = QString::number(bytesTotal / (1024 * 1024));

    //QString 转为INT 类型
    int received = strReceived.toInt();
    int total = strTotal.toInt();

    //设置进度条的最大值 和 进度值
    progress->setValue(received);
    progress->setMaximum(total);

    //已用时间
    int useTime = time.elapsed();

    //下载速度 接收到的值 / 已用时间
    double speed = bytesReceived / useTime;

    //剩余时间
    double leftTime = bytesTotal / speed / 1000 - useTime / 1000;

    int intLeftTime = (int) leftTime;
    int leftHour = intLeftTime / 3600;
    int leftMin = intLeftTime % 3600 / 60;
    int leftSec = intLeftTime % 60;

    //格式化文本窗
    //文件总大小  bytesTotal / (1024 * 1024) MB
    //已经下载    bytesReceived / (1024 * 1024 MB
    //下载速度    已经下载 / 已经用时  将毫秒改为秒 *1000  将bytes改为MB (1024 * 1024)
    //总时间      总大小 / 下载速度  /秒
    //剩余时间    总时间 - 已用时间

    textEdit->setText(QString("文件大小: %1MB    已下载: %2MB\n\n下载速度: %3MB/s\n\n剩余时间: %4小时 %5分钟 %6秒")
                      .arg(total)
                      .arg(received)
                      .arg(speed * 1000 / (1024 * 1024), 0, 'f', 2)
                      .arg(leftHour)
                      .arg(leftMin)
                      .arg(leftSec));
}
